home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
crop.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
19KB
|
759 lines
/*
* $Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
* Purpose:
* Eliminate part of the image. Bounding region can be a rectangular
* or a circular region (to be implemented).
*
* Limitations:
* only the viewable region is croppable.
*/
#if !defined(lint) && defined(F_ID)
char *id_crop = "$Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
/******************* defines and limits **********************/
#define CMAX 50 /* max border thru pop-pup */
#define CROSSL 16 /* cross lenght */
/******************* local variables ***************************/
static Rect_t imgbound, *ibr; /* input image region */
static Rect_t regbound, *cbr; /* current crop region */
static int bcolor = 1; /* rubber color */
static int cobjs; /* region defs */
static int ioffx, ioffy; /* input & current image loc diff */
static int offx, offy; /* distance from (x,y) to image */
static int croped; /* true if image is altered */
static IPTR oim; /* local copy of image ptr */
/****************** local functions **************************/
static int crop_init(IPTR, int);/* initialize */
static int crop_finish(IPTR); /* clean up */
static int crop_it(IPTR); /* do the cropping */
static int crop_popup(IPTR); /* handle popup */
static void crop_undo(IPTR); /* Undo last crop */
static void crop_save(IPTR); /* change image */
static void crop_add_frame(int);/* enlarge region */
static void ras_fill(IPTR, int *);
/********************************************************************
* Global entry point for cropping.
*
*******************************************************************/
int
do_crop(IPTR im)
{
int done;
short val;
long dev;
/* initial rubber band position and size */
if (crop_init(im, 0) < 0)
return -1;
/* how to handle window manager's resizing, re-position etc */
install_wm_handler(crop_init);
/* make a local copy for undo */
if ((oim = img_dup(im)) == 0)
{
Bark("Crop", "Can't save image");
return -1;
}
/*
* loop until cancel or done, which is set either by ESC key or by popup
* entry
*/
croped = done = 0;
do
{
dev = rubber_info(win_id, &val, &cbr->x, &cbr->y,
&cbr->w, &cbr->h, bcolor, CROSSL);
/*
* remember current location relative to lower left corner of the
* image. Need this info for window manager repaint events
*/
offx = cbr->x - im->xi;
offy = cbr->y - im->yi;
ioffx = ibr->x - im->xi;
ioffy = ibr->y - im->yi;
switch (bit_handle_event(dev, val))
{
case KEYBD:
done = (val == 27) ? -1 : 0;
break;
case ESCKEY:
done = (val > 0) ? -1 : 0;
break;
case MENUBUTTON:
done = val && crop_popup(im);
break;
default:
M_info("Crop", "Unknown event %ld %d", dev, val);
break;
}
}
while (!done);
rubber_finish();
if (done == -1) /* cancel */
crop_undo(im);
return crop_finish(im);
}
/**************************************************************
* Initialize the CROP function: initial size and location
* of the rubber band. This function also handles window resizing,
* reposition events (as far as rubber band location is concerned.
*****************************************************************/
/*ARGSUSED */
static int
crop_init(IPTR im, int wme)
{
/* default limit is the larger of the window & image */
set_rubber_bounds(0, Min(1, im->xi - 1), Min(1, im->yi - 1),
Max(win_w - 1, im->w + 2),
Max(win_h - 1, im->h + 2));
if (wme)
{
/*
* true wme indicates there is a possibility that window might be
* reszied. Figure out there the new rubber band should be where it
* has a constant relationship to image
*/
cbr->x = im->xi + offx;
cbr->y = im->yi + offy;
/*
* must not use im->xi & im->yi as the filling bounds are against
* the OLD image bounds, not the stuff after internal filling. This
* is relevent only redraw occurs while in color selection routine
*/
ibr->x = im->xi + ioffx;
ibr->y = im->yi + ioffy;
}
else
{
ibr = &imgbound;
cbr = ®bound;
set_rect(ibr, im->xi, im->yi, im->w, im->h);
/* initial size, default to viewable region */
copy_rect(cbr, union_rect(make_rect(1, 1, win_w, win_h), ibr));
offx = offy = ioffx = ioffy = 0;
/* make the box larger by one pixel on all sides */
shift_rect(cbr, -1, -1);
inc_rect(cbr, 2, 2);
/*
* must turn old polygon fill on as otherwise 1pixel sized fill is
* wrong
*/
set_current_window(win_id);
glcompat(GLC_OLDPOLYGON, 1);
}
return 0;
}
/************************************************************
* Undo all changes made so far
************************************************************/
static void
crop_undo(IPTR im)
{
if (croped)
{
/* can't use img_dup, ineffectual upon return */
img_dup_raster(im, oim);
im->ok = 1;
/* once undo, text ok to be displayed again */
im->io->display = Generic_display;
im->io->display(im, 0, 1);
crop_init(im, 0);
croped = 0;
update_image_info(im);
}
}
/***************************************************************
* make all change permenent
***************************************************************/
static void
crop_save(IPTR im)
{
if (croped)
{
free_image(oim);
oim = img_dup(im);
del_text();
del_marking();
/* re-initialize the position */
crop_init(im, 0);
croped = 0;
}
}
/*********************************************************
* make crop region n pixels larger
*******************************************************/
static void
interactive_frame(void)
{
static int fw = 3; /* frame width */
int xt1, yt1, tw, th, cc;
do
{
xt1 = cbr->x - fw;
yt1 = cbr->y - fw;
tw = cbr->w + 2 * fw;
th = cbr->h + 2 * fw;
set_current_window(win_id);
rubber_moveto(&xt1, &yt1, &tw, &th);
}
while (!(cc = getint("Enter FrameWidth:", &fw, -CMAX, CMAX, 1)));
if (cc >= 0) /* not cancel */
{
set_rect(cbr, xt1, yt1, tw, th);
}
}
static void
crop_add_frame(int n)
{
if (n < 3)
{
shift_rect(cbr, -n, -n);
inc_rect(cbr, 2 * n, 2 * n);
}
else
{
interactive_frame();
}
set_current_window(win_id);
rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
}
/************************************************************
* crop pop-up menu routines: If cancel, return -1, done 1
* else zero;
**************************************************************/
static int
crop_popup(IPTR im)
{
static long cmenu = -1;
static char *menu =
"Crop%t|DoIt|Help|BdColor|Objs|Frame1|Frame2|FrameN|"
"Auto|Save|Undo|Cancel|Done";
int done = 0, cc;
int bot, left, top, right;
/* if menu has not been made yet, make it now */
if (cmenu < 0)
cmenu = defpup(menu);
switch ((cc = dopup(cmenu)))
{
case 1: /* crop */
done = (crop_it(im) < 0);
rubber_show(bcolor);
break;
case 2: /* help */
help_cb((void *) 0, HELP_CROP);
break;
case 3: /* rubber color */
++bcolor;
bcolor %= over_pup_colors;
rubber_show(bcolor);
break;
case 4: /* rubber object */
++cobjs;
cobjs %= get_max_rubber_obj();
set_rubber_obj(cobjs);
rubber_show(bcolor);
break;
case 5: /* 1 pixel larger */
case 6: /* 2 pixel larger */
case 7: /* n-pixel larger */
crop_add_frame(cc - 4);
break;
case 8: /* auto */
if (img_get_border(im, &bot, &left, &top, &right, 1))
break;
set_rect(ibr, ibr->x + left, ibr->y + bot,
(im->w + 2) - left - right,
(im->h + 2) - top - bot);
set_current_window(win_id);
rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
break;
case 9: /* save */
crop_save(im);
break;
case 10: /* undo */
crop_undo(im);
break;
case 11: /* undo and return */
crop_undo(im);
done = -1;
break;
case 12:
done = 1;
break;
}
return done;
}
/*******************************************************************
* Gotten the crop region icb and corresponding raster matrix m,
* insert into image structure
*******************************************************************/
static void
crop_update(IPTR im, void *m, Rect_t * icb)
{
/* update the image structure */
im->w = icb->w;
im->h = icb->h;
fill_image_struct(im, m, im->h, im->w, im->type);
/* supress centering */
im->xi = icb->x;
im->yi = icb->y;
im->xf = icb->x + icb->w - 1;
im->yf = icb->y + icb->h - 1;
}
/*******************************************************************
* Cropping by core raster manipualtions.
* If there are text or sgfs on screen, framebuffer read can not be
* avoided because lack of background rendering support (No Pixmap) in GL.
* Well, can't change that.
*
* For regions outside the image, screen will be read and may be
* refilled later.
*
********************************************************************/
static int
ras_crop(IPTR im)
{
void *m, *om = 0;
Rect_t cb;
const Rect_t *iu, *ir = img_rect(im);
Rect_t *icb = &cb;
/* get the interior of the bounding region */
copy_rect(icb, cbr);
shift_rect(icb, 1, 1);
inc_rect(icb, -2, -2);
M_info("Crop", "Internal cropping");
show_busy(0);
/*
* if crop region is completely within image, the piece of the image,
* corresponding to the crop region will be the current image. Much
* faster than the mixed regions.
*/
if (cover_rect(ir, icb))
{
m = equal_rect(ir, icb) ?
im->mraster : get_subimage(im, icb->x, icb->y, icb->w, icb->h);
crop_update(im, m, icb);
if (m != im->mraster)
free_mat(m);
end_busy();
return 0;
}
/*
* mixed regions. Always read frame buffer first and then insert the
* raster corresponding to crop region from core directly into new image
* matrix
*/
if (!(m = get_mat(icb->h, icb->w, im->esize)))
return -1;
Rectread(icb->x, icb->y,
icb->x + icb->w - 1, icb->y + icb->h - 1, ((char **) m)[0]);
/* get the union of the two regions */
if ((iu = union_rect(ir = img_rect(im), icb)))
{
om = equal_rect(ir, iu) ?
im->mraster : get_subimage(im, iu->x, iu->y, iu->w, iu->h);
put_submat(m, icb->h, icb->w, om, iu->y - icb->y,
iu->x - icb->x, iu->h, iu->w, im->esize);
}
else
{
M_warn("Crop", "No union found");
}
if (om && om != im->mraster)
free_mat(om);
crop_update(im, m, icb);
end_busy();
return 0;
}
/*********************************************************************
* Cropping via framebuffer read. Could look bad if on Indigoes
* or machines with less than 24 bits framebuffer
********************************************************************/
static int
fb_crop(IPTR im)
{
/* the bounding rect is 1 pixel larger than both sides */
return read_screen(im, cbr->x + 1, cbr->y + 1, cbr->w - 2, cbr->h - 2);
}
/*******************************************************************
* When the cropping region is larger than current image, have a choice
* to fill the empty regions. This function does the interactive
* part of the filling. The actually filling is done by memory copy
* in crop_it
*******************************************************************/
/* default fill color */
static int lc[4] =
{
0, 0, 0, 0
};
/***************************************************************
* Fill the region that is not the union of (x,y, bw, bh)
* and (xi, yi, xf, yf)
**************************************************************/
static void
screen_fill_only(void)
{
int fx2 = cbr->x + cbr->w - 1;
int fy2 = cbr->y + cbr->h - 1;
int xf = ibr->x + ibr->w - 1;
int yf = ibr->y + ibr->h - 1;
if (union_rect(ibr, cbr) == 0)
{
rectfi(cbr->x, cbr->y, cbr->x + cbr->w - 1, cbr->y + cbr->h - 1);
return;
}
if (cbr->x < ibr->x - 1)
{
rectfi(cbr->x + 1, cbr->y + 1, ibr->x - 1, fy2 - 1);
}
if (cbr->y < ibr->y - 1)
{
rectfi(cbr->x + 1, cbr->y + 1, fx2 - 1, ibr->y - 1);
}
if (fx2 > xf + 1)
{
rectfi(xf + 1, cbr->y + 1, fx2 - 1, fy2 - 1);
}
if (fy2 > yf + 1)
{
rectfi(cbr->x + 1, yf + 1, fx2 - 1, fy2 - 1);
}
}
/**********************************************************************
* Fill and show it
*********************************************************************/
static void
screen_fill(int c[])
{
set_current_window(win_id);
reshapeviewport();
Color((RGB2CPACK(c[0], c[1], c[2])), c[3]);
screen_fill_only();
if (double_buf)
{
swapbuffers();
screen_fill_only();
}
}
/*********************************************************************
* Similar to screen_fill, but fill the raster instead as well
********************************************************************/
static void
ras_fill(IPTR im, int *c)
{
void *m = im->mraster;
size_t e = im->esize;
rgba_t fc;
int delta;
int x2 = cbr->x + cbr->w - 1;
int y2 = cbr->y + cbr->h - 1;
int iw = im->w, ih = im->h;
int xf = ibr->x + ibr->w - 1;
int yf = ibr->y + ibr->h - 1;
if (c == 0)
c = lc;
fc = (IS_CI(im)) ? c[3] : (rgba_t) Pack(c[0], c[1], c[2]);
#if 1
/* completely disjoint */
if (union_rect(ibr, img_rect(im)) == 0)
{
init_mat(im->mraster, im->h, im->w, im->esize, fc);
screen_fill(c);
return;
}
#endif
/* fill_submat uses ( r = r1; r<=r2; r++) */
if ((delta = Min(ibr->x, x2 - 1) - cbr->x - 1) > 0)
{
fill_submat(m, 0, ih - 1, 0, delta - 1, fc, e);
}
if ((delta = Min(ibr->y, yf - 1) - cbr->y - 1) > 0)
{
fill_submat(m, 0, delta - 1, 0, iw - 1, fc, e);
}
if ((delta = x2 - 1 - Max(xf, cbr->x + 1)) > 0)
{
fill_submat(m, 0, ih - 1, iw - delta, iw - 1, fc, e);
}
if ((delta = y2 - 1 - Max(yf, cbr->y + 1)) > 0)
{
fill_submat(m, ih - delta, ih - 1, 0, iw - 1, fc, e);
}
/* also show on screen */
screen_fill(c);
}
/******************************************************************
* actually doing the crop by calling other routine if necessary
********************************************************************/
static int
crop_it(IPTR im)
{
short val;
int internal, fill;
Rect_t trect;
#ifdef MTRACE
M_trace("CropIt", "Entering");
#endif
rubber_hide();
/* true region is 1pixel larger on all sides */
copy_rect(&trect, cbr);
shift_rect(&trect, 1, 1);
inc_rect(&trect, -2, -2);
set_current_window(win_id);
frontbuffer(1);
clear_outside_rect(&trect);
/* disable text & sgf displaying */
im->io->display = display_image;
/* replace raster if no text and sgfs */
internal = (!always_readscrn && !number_of_text() && !number_of_sgf());
set_current_window(win_id);
reshapeviewport();
if ((internal ? ras_crop : fb_crop) (im) < 0)
return -1;
update_image_info(im);
/* fill if neccessary. crop_fill == 0 turns off fill */
fill = (!cover_rect(ibr, &trect) && (crop_fill == 2 ||
(crop_fill == 1 && yes_no("FillCropRegion", "", "Fill ?", 0))));
/* do redraw and eat other events */
(void) bit_qread(&val);
/*
* remember where the bounds and old image locatations relative to
* cropped image. Useful if redraw occurs to re-display rubber band
*/
ioffx = ibr->x - im->xi;
ioffy = ibr->y - im->yi;
offx = cbr->x - im->xi;
offy = cbr->y - im->yi;
if (fill)
{
/* show default color */
ras_fill(im, lc);
/* what to do if color changes */
set_getcolor_cb(screen_fill);
/*
* never returns unless form is finished. For every color change,
* screen_fill will be called
*/
get_color(im, lc, 1); /* block */
/*
* could stick the following into screen_fill, but it could be
* slow. This way although if unknown repaints occurs, the screen
* could be messed up, but the image is not damaged and we have a
* much better response
*/
/*
* do final actually filling. It is always a good thing to fill
* internally
*/
ras_fill(im, lc);
}
croped = 1;
frontbuffer(!double_buf);
#ifdef MTRACE
M_trace("CropIt", "Returning");
#endif
return 0;
}
/**********************************************************************
* clean up
**********************************************************************/
static int
crop_finish(IPTR im)
{
if (im->ok > 0)
{
free_image(oim);
}
else
{
Bark("Crop", "Something is not right");
free_image_mem(im);
memcpy(im, oim, sizeof(*oim));
croped = 0;
}
im->ok = 1;
if (croped)
{
if (!keepmisc)
{
del_text();
del_marking();
}
im->io->display(im, -1, 1);
}
/*
* since there is no mask set, if framebuffer is read, we got full
* 12bits, need to mask off the un-used one otherwise colormap overflown.
*/
if (IS_CI(im))
do_ci_mask(im->raster, im->w * im->h, im->cmap->colors - 1);
remove_wm_handler(crop_init);
im->io->display = Generic_display;
if (double_buf)
im->io->display(im, 0, 1);
return 0;
}